﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting;
using System.Text;
using System.Xml.Linq;
using System.Web;
using com.eforceglobal.crux.configuration.DTOs;
using com.eforceglobal.crux.BusinessObjects.Enums;
using com.eforceglobal.crux.security.EncryptionAndHashing.Enums;
using com.eforceglobal.crux.DTOs.Configuration;

namespace com.eforceglobal.crux.configuration
{
    public class CruxConfigurationManager
    {
        //TODO: Cache this file instead of reading from IO each time for faster access.
        //TODO: Doing this as static might not effect the changes and allow them to
        //happen independently.
        
        private static XDocument LoadConfigurationDocument()
        {
            XDocument xDocument = (XDocument)HttpRuntime.Cache.Get("CruxConfigurationFile");
            if (xDocument == null)
            {
                string fileName = HttpContext.Current.Server.MapPath("~/SiteConfig/Crux.config");
                xDocument = XDocument.Load(fileName);
                HttpRuntime.Cache.Add("CruxConfigurationFile", xDocument, new System.Web.Caching.CacheDependency(fileName), DateTime.Now.AddDays(7),
                TimeSpan.Zero, System.Web.Caching.CacheItemPriority.High, null);
            }
            return xDocument;
        }

        

        public static ViewInformation GetViewInformation(string ViewName)
        {
            ViewInformation viewInformation = new ViewInformation();
            XDocument cruxConfigurationDocument = LoadConfigurationDocument();
            XElement viewNode = cruxConfigurationDocument.Element("CruxConfigurations").Element("UserInterface")
                                         .Element("Views").Elements("View")
                                         .Single(p=>p.Attribute("Name").Value == ViewName);
            
            viewInformation.ViewName = viewNode.Attribute("Name").Value;
            viewInformation.ViewTitle = viewNode.Attribute("Title").Value;
            viewInformation.IsInternal = bool.Parse(viewNode.Attribute("InternalView").Value);
            
            viewInformation.ViewUrl = viewNode.Attribute("URL").Value;

            if (viewInformation.IsInternal)
                viewInformation.ViewUrl = GetApplicationPath() + viewInformation.ViewUrl;

            if(viewNode.Attribute("Section")!=null)
                viewInformation.ViewSection = viewNode.Attribute("Section").Value;
            viewInformation.RoleConfigurationInformation = GetRoleInformationForView(ViewName);
            return viewInformation;

        }

        
        public static PasswordStorageType GetPasswordStorageType()
        {
            XDocument curxConfigurationDocument = LoadConfigurationDocument();
            string passwordStorageTypeText = curxConfigurationDocument.Element("CruxConfigurations")
                                         .Element("Security").Element("PasswordStorage")
                                         .Element("Password").Attribute("StorageType")
                                         .Value.ToLower();
            PasswordStorageType passwordStorageType =
                (PasswordStorageType)Enum.Parse(typeof(PasswordStorageType), passwordStorageTypeText);
            return passwordStorageType;
            
        }

        public static string GetViewTitle(string ViewName)
        {
            return GetViewInformation(ViewName).ViewTitle;
        }

        public static string GetApplicationPath()
        {
            XDocument cruxConfigurationDocument = LoadConfigurationDocument();
              return  cruxConfigurationDocument.Element("CruxConfigurations")
                  .Element("ApplicationSettings")
                  .Element("GeneralSettings")
                  .Element("ApplicationPath").Attribute("URL").Value;
           
        }

        public static string GetCruxDBConnectionString()
        {
            XDocument cruxConfigurationDocument = LoadConfigurationDocument();
            return cruxConfigurationDocument.Element("CruxConfigurations")
                .Element("ApplicationSettings")
                .Element("DatabaseSettings")
                .Element("CruxDB").Attribute("ConnectionString").Value;
        }

        public static string GetCruxApplicationLogDBConnectionString()
        {
            XDocument cruxConfigurationDocument = LoadConfigurationDocument();
            return cruxConfigurationDocument.Element("CruxConfigurations")
                .Element("ApplicationSettings")
                .Element("DatabaseSettings")
                .Element("ApplicationLogDB").Attribute("ConnectionString").Value;
        }

        public static bool SupportCompanyRepresentatives()
        {
            XDocument cruxConfigurationDocument = LoadConfigurationDocument();
            string supportsCompanyRepresentatives =
                 cruxConfigurationDocument.Element("CruxConfigurations")
                .Element("ApplicationSettings")
                .Element("ApplicationFeatures")
                .Element("Support").Attribute("CompanyRepresentatives").Value;
            return bool.Parse(supportsCompanyRepresentatives);
        }

        public static bool SupportLocationRepresentatives()
        {
            XDocument cruxConfigurationDocument = LoadConfigurationDocument();
            string supportsCompanyRepresentatives =
                 cruxConfigurationDocument.Element("CruxConfigurations")
                .Element("ApplicationSettings")
                .Element("ApplicationFeatures")
                .Element("Support").Attribute("LocationRepresentatives").Value;
            return bool.Parse(supportsCompanyRepresentatives);
        }


        public static string GetClassDetailsForSecurityManager(string SecurityManagerName)
        {
            ViewInformation viewInformation = new ViewInformation();
            XDocument cruxConfigurationDocument = LoadConfigurationDocument();
            XElement viewNode = cruxConfigurationDocument.Element("CruxConfigurations")
                                         .Element("Security").Element("Providers").Elements("SecurityProvider")
               .Single(p=>p.Attribute("Name").Value=="CruxSecurityProvider");
            string ClassDetails = viewNode.Attribute("Type").Value;
            return ClassDetails;
        }

        public static NavigationInformation GetNavigationInformation(string NavigationItemName)
        {
            NavigationInformation navigationInformation = new NavigationInformation();
            XDocument cruxConfigurationDocument = LoadConfigurationDocument();
            XElement navigationNode = cruxConfigurationDocument.Element("CruxConfigurations")
                                                .Element("UserInterface").Element("Navigations").Elements("Navigation")
                .Single(p => p.Attribute("Name").Value == NavigationItemName);
            navigationInformation.NaviagtionItemName = navigationNode.Attribute("Name").Value;
            navigationInformation.NavigationItemDescription = navigationNode.Attribute("Description").Value;
            string viewName = navigationNode.Attribute("ViewName").Value;
            navigationInformation.ConnectedViewName = viewName;
            ViewInformation viewInformation = GetViewInformation(viewName);
            navigationInformation.ConnectedViewURL = viewInformation.ViewUrl;
            navigationInformation.NavigationItemSortOrder = int.Parse(navigationNode.Attribute("SortOrder").Value);
            navigationInformation.IsNavigationViewInternal = viewInformation.IsInternal;
                navigationInformation.RoleConfigurationInformation =
                GetRoleInformationForView(navigationNode.Attribute("ViewName").Value);
            return navigationInformation;
        }

        public static List<NavigationInformation> GetAllNavigationItems()
        {
            List<NavigationInformation> navigationInformations = new List<NavigationInformation>();
            XDocument cruxConfigurationDocument = LoadConfigurationDocument();
            IEnumerable<XElement> navigationItems = cruxConfigurationDocument.Element("CruxConfigurations")
                .Element("UserInterface").Element("Navigations").Elements("Navigation");
            foreach (XElement navigationItem in navigationItems)
            {
                NavigationInformation navigationInformation = new NavigationInformation();
                string NavigationItemName = navigationItem.Attribute("Name").Value;
                navigationInformation = GetNavigationInformation(NavigationItemName);
                navigationInformations.Add(navigationInformation);
            }
            return navigationInformations;
        }
        
        private static RoleConfigurationInformation GetRoleInformationForView(string ViewName)
        {
            ViewInformation viewInformation = new ViewInformation();
            XDocument cruxConfigurationDocument = LoadConfigurationDocument();
            XElement viewNode = cruxConfigurationDocument.Element("CruxConfigurations").Element("UserInterface").Element("Views")
                .Elements("View")
                .Single(p => p.Attribute("Name").Value == ViewName);

            string roleConditionValue = "";
            if(viewNode.Element("Roles").Attribute("Condition")!=null)
                roleConditionValue = viewNode.Element("Roles").Attribute("Condition").Value.ToLower();

            if (roleConditionValue.Trim() == "*") roleConditionValue = Conditions.all.ToString();
            else if (roleConditionValue.Trim().ToLower() == "single") roleConditionValue = Conditions.single.ToString();
            else if (string.IsNullOrEmpty(roleConditionValue.Trim())) roleConditionValue = Conditions.none.ToString();

            RoleConfigurationInformation roleConfigurationInformation = new RoleConfigurationInformation();
            roleConfigurationInformation.RoleCondition = (Conditions)Enum.Parse(typeof(Conditions),roleConditionValue);
            IEnumerable<XElement> roleElements = viewNode.Element("Roles").Elements("Role");
            foreach (XElement role in roleElements)
            {
                roleConfigurationInformation.RoleNames.Add(role.Attribute("Name").Value); 
            }

            return roleConfigurationInformation;
        }

        public static EmailNotificationActionInformation GetEmailNotificationSettings(string ActionName)
        {
            XDocument cruxConfigurationDocument = LoadConfigurationDocument();
            XElement notificationsNode = cruxConfigurationDocument.Element("CruxConfigurations")
                                         .Element("Notifications")
                                         .Element("EmailNotifications");
            EmailNotificationInformation emailNotificationInformation 
                = GetEmailNotificationInformation(notificationsNode);

            XElement actionNotificationNode = notificationsNode.Element("NotificationActions")
                                               .Elements("Action")
                                               .SingleOrDefault(p => p.Attribute("Name").Value == ActionName);
            EmailNotificationActionInformation emailActionNotification = GetEmailNotificationActionInformation
                (actionNotificationNode);

            emailActionNotification.EmailNotificationInformation = emailNotificationInformation;

            return emailActionNotification;
        }

        private static EmailNotificationInformation GetEmailNotificationInformation(XElement EmailNotificiationNode)
        {
            EmailNotificationInformation emailNotificationInformation = new EmailNotificationInformation();
            emailNotificationInformation.Notify = bool.Parse(EmailNotificiationNode.Attribute("Notify").Value);
            emailNotificationInformation.UseSSL = bool.Parse(EmailNotificiationNode.Attribute("UseSSL").Value);
            emailNotificationInformation.UserName = EmailNotificiationNode.Attribute("UserName").Value;
            emailNotificationInformation.EmailPassword = EmailNotificiationNode.Attribute("Password").Value;
            emailNotificationInformation.Port = int.Parse(EmailNotificiationNode.Attribute("Port").Value);
            emailNotificationInformation.SmtpServer = EmailNotificiationNode.Attribute("SmtpServer").Value;
            emailNotificationInformation.FromAddress = EmailNotificiationNode.Attribute("FromAddress").Value;
            emailNotificationInformation.SendInHtml = bool.Parse(EmailNotificiationNode.Attribute("SendInHtml").Value);
            emailNotificationInformation.TemplateFolder = EmailNotificiationNode.Attribute("TemplateFolder").Value;
            return emailNotificationInformation;    
        }

        private static EmailNotificationActionInformation GetEmailNotificationActionInformation(XElement EmailNotificationActionNode)
        {
            EmailNotificationActionInformation actionNotification = new EmailNotificationActionInformation();
            actionNotification.ActionName = EmailNotificationActionNode.Attribute("Name").Value;
            actionNotification.Notify = bool.Parse(EmailNotificationActionNode.Attribute("Notify").Value);
            actionNotification.NotificationTemplateFile = EmailNotificationActionNode.Attribute("NotificationTemplateFile").Value;
            actionNotification.MailSubject = EmailNotificationActionNode.Attribute("MailSubject").Value;
            return actionNotification;
        }

        public static ErrorInformation GetErrorInformation(string ErrorNameOrCode)
        {
            XDocument cruxConfigurationDocument = LoadConfigurationDocument();
            XElement errorNode = cruxConfigurationDocument.Element("CruxConfigurations")
                                         .Element("ExceptionsAndErrors")
                                         .Element("Errors")
                                         .Elements("Error")
                                         .SingleOrDefault(p => p.Attribute("NameOrCode").Value == ErrorNameOrCode);

            ErrorInformation errorInformation = new ErrorInformation();
            errorInformation.ErrorNameOrCode = errorNode.Attribute("NameOrCode").Value;
            errorInformation.ErrorDescription = errorNode.Attribute("Description").Value;
            errorInformation.ProbableCause = errorNode.Attribute("ProbableCause").Value;
            errorInformation.RecommendedAction = errorNode.Attribute("RecommendedAction").Value;
            errorInformation.ShortDescription = errorNode.Attribute("ShortDescription").Value;
            return errorInformation;
        }

        public static object GetProcessor(string processName)
        {
            XDocument cruxConfigurationDocument = LoadConfigurationDocument();

            XElement parentNode = cruxConfigurationDocument.Element("CruxConfigurations")
                    .Element("ProcessorSettings");
            if (parentNode != null)
            {
                XElement node = parentNode.Elements("processor")
                     .SingleOrDefault(p => p.Attribute("Name").Value == processName);

                string assemblyName = node.Attribute("Assembly").Value; //dll/exe name
                string typeName = node.Attribute("Type").Value;

                string binPath = HttpContext.Current.Request.PhysicalApplicationPath + @"bin\" + assemblyName;
                ObjectHandle obj = null;
                obj = Activator.CreateInstanceFrom(binPath, typeName);
                if (obj != null) return obj.Unwrap();
            }

            return null;
        }

        public static string GetApplicationDefaultView()
        {
            ViewInformation viewInformation = new ViewInformation();
            XDocument cruxConfigurationDocument = LoadConfigurationDocument();
            XAttribute defaultViewName= cruxConfigurationDocument.Element("CruxConfigurations").Element("UserInterface")
                                         .Element("DefaultView").Attribute("ViewName");
            return defaultViewName.Value;
            
        }

     }
}
